﻿// use an ArgumentParser object to manage the program arguments.
using OsgViewer;

var arguments = new Osg.ArgumentParser(args);

arguments.ApplicationUsage.ApplicationName = arguments.ApplicationName;
arguments.ApplicationUsage.Description = arguments.ApplicationName + " is the standard OpenSceneGraph example which loads and visualises 3d models.";
arguments.ApplicationUsage.CommandLineUsage = arguments.ApplicationName + " [options] filename ...";
arguments.ApplicationUsage.addCommandLineOption("--image <filename>", "Load an image and render it on a quad");
arguments.ApplicationUsage.addCommandLineOption("--dem <filename>", "Load an image/DEM and render it on a HeightField");
arguments.ApplicationUsage.addCommandLineOption("--login <url> <username> <password>", "Provide authentication information for http file access.");
arguments.ApplicationUsage.addCommandLineOption("-p <filename>", "Play specified camera path animation file, previously saved with 'z' key.");
arguments.ApplicationUsage.addCommandLineOption("--speed <factor>", "Speed factor for animation playing (1 == normal speed).");
arguments.ApplicationUsage.addCommandLineOption("--device <device-name>", "add named device to the viewer");
arguments.ApplicationUsage.addCommandLineOption("--stats", "print out load and compile timing stats");

var viewer = new Viewer(arguments);

var helpType = Osg.ApplicationUsage.Type.NO_HELP;
if (helpType == arguments.readHelpType)
{
    //arguments.ApplicationUsage.write(cout, helpType);
    //return;
}

// report any errors if they have occurred when parsing the program arguments.
if (arguments.errors())
{
    //arguments.writeErrorMessages(cout);
    return;
}

if (arguments.argc <= 1)
{
    //arguments.ApplicationUsage.write(cout, Osg.ApplicationUsage::COMMAND_LINE_OPTION);
    return;
}

bool printStats = arguments.read("--stats");

string url, username, password;
while (arguments.read("--login", out url, out username, out password))
{
    OsgDB.Registry.instance().getOrCreateAuthenticationMap().addAuthenticationDetails(
        url,
        new OsgDB.AuthenticationDetails(username, password)
    );
}

string device;
while (arguments.read("--device", out device))
{
    var dev = OsgDB._.readObjectFile(device) as OsgGA.Device;
    if (dev != null)
    {
        viewer.addDevice(dev);
    }
}

// set up the camera manipulators.
{
    var keyswitchManipulator = new OsgGA.KeySwitchMatrixManipulator();

    keyswitchManipulator.addMatrixManipulator('1', "Trackball", new OsgGA.TrackballManipulator());
    keyswitchManipulator.addMatrixManipulator('2', "Flight", new OsgGA.FlightManipulator());
    keyswitchManipulator.addMatrixManipulator('3', "Drive", new OsgGA.DriveManipulator());
    keyswitchManipulator.addMatrixManipulator('4', "Terrain", new OsgGA.TerrainManipulator());
    keyswitchManipulator.addMatrixManipulator('5', "Orbit", new OsgGA.OrbitManipulator());
    keyswitchManipulator.addMatrixManipulator('6', "FirstPerson", new OsgGA.FirstPersonManipulator());
    keyswitchManipulator.addMatrixManipulator('7', "Spherical", new OsgGA.SphericalManipulator());

    string pathfile;
    double animationSpeed = 1.0;
    while (arguments.read("--speed", out animationSpeed)) { }
    char keyForAnimationPath = '8';
    while (arguments.read("-p", out pathfile))
    {
        var apm = new OsgGA.AnimationPathManipulator(pathfile);
        if (apm != null && !apm.AnimationPath.empty)
        {
            apm.TimeScale = animationSpeed;

            uint num = keyswitchManipulator.NumMatrixManipulators;
            keyswitchManipulator.addMatrixManipulator(keyForAnimationPath, "Path", apm);
            keyswitchManipulator.selectMatrixManipulator(num);
            ++keyForAnimationPath;
        }
    }

    viewer.CameraManipulator = keyswitchManipulator;
}

// add the state manipulator
viewer.addEventHandler(new OsgGA.StateSetManipulator(viewer.Camera.getOrCreateStateSet()));

// add the thread model handler
viewer.addEventHandler(new OsgViewer.ThreadingHandler());

// add the window size toggle handler
viewer.addEventHandler(new OsgViewer.WindowSizeHandler());

// add the stats handler
viewer.addEventHandler(new OsgViewer.StatsHandler());

// add the help handler
viewer.addEventHandler(new OsgViewer.HelpHandler(arguments.ApplicationUsage));

// add the record camera path handler
viewer.addEventHandler(new OsgViewer.RecordCameraPathHandler());

// add the LOD Scale handler
viewer.addEventHandler(new OsgViewer.LODScaleHandler());

// add the screen capture handler
viewer.addEventHandler(new OsgViewer.ScreenCaptureHandler());

var elapsedTime = new Osg.ElapsedTime();

// load the data
var loadedModel = OsgDB._.readNodeFiles(arguments);
if (loadedModel == null)
{
    //cout << arguments.ApplicationName << ": No data loaded" << endl;
    return;
}

if (printStats)
{
    double loadTime = elapsedTime.elapsedTime_m;
    //cout << "Load time " << loadTime << "ms" << endl;

    viewer.Stats.collectStats("compile", true);
}


// any option left unread are converted into errors to write out later.
arguments.reportRemainingOptionsAsUnrecognized();

// report any errors if they have occurred when parsing the program arguments.
if (arguments.errors())
{
    //arguments.writeErrorMessages(cout);
    return;
}


// optimize the scene graph, remove redundant nodes and state etc.
var optimizer = new OsgUtil.Optimizer();
optimizer.optimize(loadedModel);

viewer.SceneData = loadedModel;

viewer.realize();

viewer.run();